<?php
/*******************************************************
*
* Page:    app_list.class
* Author:  Matthew Sturges (matt@matthewsturges.com)
* Purpose: Base class creating pageable lists
* Created: 06/29/05
* Version: 2.0
*
* Modified:
*    11/27/05 JRW   Added checkbox functionality to lists
*                   Added format for abbreviating long
*                   text fields
*
*    11/27/05 JRW   Fixed error for format to use 
*                   app_lib::nice_date instead of nonexistant
*                   stdLib::niceDate
*
*    01/26/06 TAL   Added pagination
*******************************************************/
/******************************************************
* Notes for Use
*
* This puppy is more complicated than the norm....
*
* 1. Create the object with the constructor - parameters below
*       Constructor Function
*       function app_list($query, $id_field, $default_sort_by, $default_sort_dir, $css_class_th = '', $css_class_td = '',
*       $query - the database query to produce the data to list
*       $id_field - the key field in the data - used when selecting from the list
*       $default_sort_by - The sort by field for the initial display 
*       $default_sort_dir - sort asc or desc
*       $css_class_th - css class for the <th> tags
*       $css_class_td - css class for the <td> tags
*       $cellspacing and cellpadding for the table
*       $uses_paging - true or false
*       $page_length - used for paging
*       $css_class_row - css class for odd rows
*       $css_class_even - css class for even rows - having odd and even allows shading every other row
*       $css_class_hilite - css class for the selected row
*
* 2. Add the columns with ->add_column - parameters below
*        function add_column($column_name, $column_header, $format='', $css_class='', $column_url = '', $on_click = '', $sortable = true, $blank_message = '', $type = 'text', $input_name = ''){
*       $column_name - name of the column's data from the query
*       $column_header - text to display to title the column
*       $format - 
*       $css_class - css class to use for the tds in this column 
*       $column_url 
*       $on_click - text for the onclick=''
*       $sortable - true if this column is sortable
*       $blank_message - 
*       $type -
*       $input_name -
*
*       formats: date, datetime, yesno, abbreviated.
* 
* 3. Initilize with ->init_list ($url)
*       $url - the url to open your page, include any $_GET params needed - this is used to reload the page when the user pages or sorts
*
* 4. Pour the html into your page with ->get_html - this will create a <table>
*
***********************************************************************************************************/
/**********************************************************************************************************
* TODO
* TAL app_list::css_class_td duplicates the css class in the column, remove this
* TAL app_list::css_class_th should be in the column
***********************************************************************************************************/
class app_list  {

   var $query;
   var $id_field;
   var $sort_url;
   var $default_sort_by;
   var $default_sort_dir;
   var $sort_by;
   var $sort_dir;
   var $css_class_th;
   var $css_class_td;
   var $css_class_row;
   var $css_class_even;
   var $css_class_hilite;
   var $cellspacing;
   var $cellpadding;
   var $empty_message;
   var $columns;
   var $limit; //overrides what is sent in page values
   var $uses_paging;
   var $page_length;
   var $page;
   var $page_count;
   var $table_width;
   

   var $is_initialized;
   var $row_count;


    //Constructor Function
    // $query - the database query to produce the data to list
    // $id_field - the key field in the data - used when selecting from the list
    // $default_sort_by - The sort by field for the initial display 
    // $default_sort_dir - sort asc or des
    // $css_class_th - css class for the <th> tags
    // $css_class_td - css class for the <td> tags
    // $cellspacing and cellpadding for the table
    // $uses_paging - true or false
    // $page_length - used for paging
    // $css_class_row - css class for odd rows
    // $css_class_even - css class for even rows - having odd and even allows shading every other row
    // $css_class_hilite - css class for the selected row
    function app_list($query, $id_field, $default_sort_by, $default_sort_dir, $css_class_th = '', $css_class_td = '',
            $cellspacing='1', $cellpadding='4', $uses_paging = false, $page_length='30',
            $css_class_row = '', $css_class_even = '', $css_class_hilite = '', $table_width = ''){

        $this->query = $query;
        $this->id_field = $id_field;
        $this->default_sort_by = $default_sort_by;
        $this->default_sort_dir = $default_sort_dir;
        $this->css_class_th = $css_class_th;
        $this->css_class_td = $css_class_td;
        $this->cellspacing = $cellspacing;
        $this->cellpadding = $cellpadding;
        $this->uses_paging = $uses_paging;
        $this->page_length = $page_length;
        $this->css_class_row = $css_class_row;
        $this->css_class_even = $css_class_even;
        $this->css_class_hilite = $css_class_hilite;
        $this->table_width = $table_width;
    }//end function app_list

   function init_list($page_identifier){
      $_GETPOST = array_merge($_GET, $_POST);
      
      $this->sort_url = $page_identifier;

       // if a session, check for saved page info
     // $this->page = $_SESSION['current_page'];
     // $this->page_count = $_SESSION['current_page_count'];
     // $this->page_length = $_SESSION['current_page_length'];
     // $this->sort_by = $_SESSION['current_sort_by'];
     // $this->sort_dir = $_SESSION['current_sort_dir'];

      if ($_GETPOST['page']){
         $this->page = $_GETPOST['page'];
      }
      if ($_GETPOST['page_count']){
         $this->page_count = $_GETPOST['page_count'];
      }
      if ($_GETPOST['page_length']){
         $this->page_length = $_GETPOST['page_length'];
      }
      
      if (! $this->page_length){
         $this->page_length = APP_LIST_DEFAULT_PAGE_LENGTH;
      }
      if (!$this->page){
         $this->page = 1;
         //if we're paging, and this is the first page, we want to get the total number of rows so we can
         //determine how many pages we're doing.
         $result = app_data::mysql_query($this->query);
         $numRows = mysql_num_rows($result);
         mysql_free_result($result);

         if (($numRows > $this->page_length) && ($this->page_length > 0)){
            $this->page_count = ceil($numRows / $this->page_length);
         } else {
            $this->page_count = 1;
         }
      }
      if (!$this->page_length){
         $this->page_length = APP_LIST_DEFAULT_PAGE_LENGTH;
      }//end if

      //Figure out the sort by and sort order;
      if ($_GETPOST['sort_by']){
         $this->sort_by = $_GETPOST['sort_by'];
         $this->sort_dir = $_GETPOST['sort_dir'];
      }

      //We checked the request supervariable too. Now we give up.
      if (!$this->sort_by){
         $this->sort_by = $this->default_sort_by;
         $this->sort_dir = $this->default_sort_dir;
      }

      // Save the paging data
      $_SESSION['current_list'] = $page_identifier;
      $_SESSION['current_page'] = $this->page;
      $_SESSION['current_page_count'] = $this->page_count;
      $_SESSION['current_page_length'] = $this->page_length;
      $_SESSION['current_sort_by'] = $this->sort_by;
      $_SESSION['current_sort_dir'] = $this->sort_dir;
      
      $this->is_initialized = true;
   }

   function get_html(){
      if (!$this->is_initialized){
         die ("You must initialize the list by calling init_list() before calling get_html().");
      }
      if (!isset($r)) {
         $r = "";
      }

      // Do the hilite script
      $r .= "\n<SCRIPT>\n"
            . "function hilite_row (row, which, css_class) {\n"
            . " if (which) {\n"
            . " row.className = '" . $this->css_class_hilite . "';\n"
            . " } else {\n"
            . " row.className = css_class;\n"
            . " }\n"
            . " }\n"
            . "</SCRIPT>\n";

      //Do the header row
      $r.= "<table width='" . $this->table_width . "' cellpadding='" . $this->cellpadding . "' cellspacing='" . $this->cellspacing . "'>\n";
      $r.= "  <tr class='" . $this->css_class_tr . "'>\n";
      
      $sort_by = $this->sort_by;
      $sort_dir = $this->sort_dir;
      
      //if we have a sort_url, it's because we need to pass arguments.
      if ($this->sort_url){
         if (strpos ($this->sort_url, '?') === false) {
            $url_delimiter = '?';
         } else {
            $url_delimiter = '&';
         }
      } else {
         $this->sort_url = $_SERVER['PHP_SELF'];
         $url_delimiter = '?';
      }//end if

      foreach ($this->columns as $col){
         //Can we sort on this field?
         if ($col->sortable){
            //Yes. Draw the clickable header
            if ($col->column_name == $sort_by){
               $currentSortDir = ($sort_dir == 'DESC' ? 'ASC' : 'DESC');
            }
            
            $r.= "    <th class='$this->css_class_th'><a href='" . $this->sort_url . $url_delimiter . "sort_by=" . $col->column_name . "&sort_dir=$currentSortDir" . "&page=" . $this->page . "&page_count=" . $this->page_count . "&page_length=" . $this->page_length . "'>" . $col->column_header . "</a></th>\n";
         } else {
            //No. Just draw the name.
            $r.= "    <th class='$this->css_class_th'>" . $col->column_header . "</th>\n";
         }//end if
      }//end foreach
      $r.= "  </tr>\n";
      
      //Now, parse the rows
      $query = $this->query;

      $query.= " ORDER BY $sort_by $sort_dir";
       
      //Determine the limits
      if ($this->uses_paging){
         //Do the page limit
         $page_offset = ($this->page - 1) * $this->page_length;
         $query.= " LIMIT $page_offset, " . $this->page_length;
      } elseif ($this->limit){
         $query.= " LIMIT $this->limit";
      }
      $this->row_count = 0;
      $result = app_data::mysql_query($query);
      if (mysql_num_rows($result) > 0){
         while ($row = mysql_fetch_assoc($result)){
            $r.= $this->get_row($row);
         }//end while
      } else {
         $r.= $this->get_empty_row();
      }//end if

//$r .= "<tr><td colspan='" . sizeof ($this->columns) . "'>search: " . $query . "</td></tr>";

      	
// CDK added this because when I turn paging off, these buttons still get drawn.
if ($this->uses_paging){

      //draw the first page and previous buttons, but disabled if this IS the first page.
      $r .= "<tr><td colspan='" . sizeof ($this->columns) . "'><table><tr>";
      if ($this->page == 1) {
         $r .= "<td class='tiny'><input class='disabled' type='button' disabled value=' << '></td>";
         $r .="<td class='tiny'><input class='disabled' type='button' disabled value=' < '></td>";
      } else {
         $r .= "<td class='tiny'><input type='button' name='page_move' title='Go Back to Page 1' value = ' << ' onclick='location.href=(\""
             . $this->get_page_url('first') . "\");'></td>";
         $r .= "<td class='tiny'><input type='button' name='page_move' title='Go Back One Page' value = ' < ' onclick='location.href=(\""
             . $this->get_page_url('previous') . "\");'></td>";
      } //END if
      
      //Now, a dropdown with all the pages
      //$r .= "<td class='tiny'>jump to: <select name='page_select' onChange='this.form.submit();'>";
      //for ($j = 1; $j <= $this->page_count; $j++){
      //$selected = ($j == $this->page ? ' SELECTED' : '');
      //   $r .= "<option value='$j'$selected>$j</option>";
      //}// END for
      //$r .= "</select></td>";
      
      //draw the last page and next buttons, but disabled if this IS the last page.
      if ($this->page == $this->page_count) {
         $r .= "<td class='tiny'><input class='disabled' type='button' disabled value=' > '></td>";
         $r .= "<td class='tiny'><input class='disabled' type='button' disabled value=' >> '></td>";
      } else {
         $r .= "<td class='tiny'><input type='button' name='page_move' title='Advance One Page' value = ' > ' onclick='location.href=(\"". $this->get_page_url('next') . "\");'></td>";
         $r .= "<td class='tiny'><input type='button' name='page_move' title='Advance to the Last Page' value = ' >> ' onclick='location.href=(\"". $this->get_page_url('last') . "\");'></td>";
      } //END if
      $r .= "</tr></table></td></tr>";
      
 } // end if uses paging

      $r.= "</table>";
      mysql_free_result($result);

      $this->sort_by="";
      return $r;
   }//end function

   function get_row($row){
      //Begin the row

      if (($this->row_count % 2) != 0) {
         $r = "  <tr class='" . $this->css_class_row . "'"
                                       . " onMouseOver='hilite_row(this, true, \"". $this->css_class_row . "\");'"
                                       . " onMouseOut='hilite_row(this, false, \"" . $this->css_class_row . "\");'>";
      } else { // if even row
          $r = "  <tr class='" . $this->css_class_even . "'"
                                       . " onMouseOver='hilite_row(this, true, \"" . $this->css_class_even . "\");'"
                                       . " onMouseOut='hilite_row(this, false, \"" . $this->css_class_even . "\");'>";
      } // end else
      $this->row_count ++;
//	  echo '<pre>';print_r($this);echo '</pre>';
      foreach ($this->columns as $col){
         //if the url has an %%%id%%% token, then replace with the id
         $url = $col->column_url;
         $target = $col->target;
         
         $on_click = $col->on_click;
         $url = str_replace('%%%id%%%', $row[$this->id_field], $url);
         $on_click = str_replace('%%%id%%%', $row[$this->id_field], $on_click);
         
         //Check for any other %%% tokens
         $pattern = "%%%[A-Za-z0-9_]+%%%";
         //$pattern = "\%\%\%pag_path\%\%\%";
         $regs = array();
         
         //Check in the URL
         while (ereg($pattern, $url, $regs)){
            $token = $regs[0];
            $token = str_replace('%%%', '', $token);
            $url = str_replace($regs[0], $row[$token], $url);
         }

         //Check in the onClick
         while (ereg($pattern, $on_click, $regs)){
            $token = $regs[0];
            $token = str_replace('%%%', '', $token);
            $on_click = str_replace($regs[0], $row[$token], $on_click);
         }
         
         //get the value of this particular column and format it if necessary.
         if($col->type == 'text'){
            $value = $col->format_value($row[$col->column_name]);
         }
         elseif($col->type == 'checkbox'){
            $value = "<input type='checkbox' name='" . $col->input_name . "[]' value='" . $row[$this->id_field] . "'>";
         }
         // CDK -- added below custom type so as not to interfere with any other checkbox usage that
         elseif($col->type == 'reviewer_checkbox') {
            $value = "<input type='checkbox' name='" . $col->input_name . "[]' value='" . $row[$this->id_field] ."'";
            
            if( $row[permission_id] == MEM_TYPE_REVIEWER ) {
                $value .= "checked='yes' ";
            }
            
            $value .= "/>";
            
            if( $row[permission_id] == MEM_TYPE_REVIEWER ) {
               // adding a reviewer is no big deal, but removing them is if they have assigned reviews
               // so we need to know who WAS a reviewer when the new list of reviewers is submitted
               $value .= "<input type='hidden' name='was_reviewer[]' value='" . $row[$this->id_field] ."' />";
            }
            
         }
         else{
            $value = "test";
         } /* End If */
         
         if (!$value) 
            $value = $col->blank_message;
         
//         $css_class = ($col->css_class == '' ? $this->css_class_td : $col->css_class);
         $css_class = $col->css_class;
         //Begin the table cell
         $r.= "    <td class='" . $css_class . "'>";
         
         if($target !='')
         	$tgt = 'target="'.$target.'"';
         else 
         	$tgt = '';
         
         //was a url or an onClick passed?
         if ($url || $on_click) {
            //draw it with a linky-loo
            $r.= "<a href='$url' ".$tgt." onClick='$on_click'>$value</a>";
         } else {
            //just draw the value
            $r.= $value;
         }//end if
         
         //End the table cell
         $r.= "</td>\n";
       }//end foreach
      
      $r.= "  </tr>";
      return $r;
   }//end function get_row();

    function get_empty_row(){
        $empty_message = $this->empty_message;
        if (!$empty_message) $empty_message = APP_LIST_DEFAULT_EMPTY_QUERY_MESSAGE;
        $colspan = count($this->columns);
        $r = "    <tr class='row'><td colspan='$colspan' class='$this->css_class_td'><i>$empty_message</i></td></tr>\n";
        return $r;
    }

    // $column_name - name of the column's data from the query
    // $column_header - text to display to title the column
    // $format - 
    // $css_class - css class to use for the tds in this column 
    // $column_url 
    // $on_click - text for the onclick=''
    // $sortable - true if this column is sortable
    // $blank_message - 
    // $type -
    // $input_name -
    function add_column($column_name, $column_header, $format='', $css_class='', $column_url = '', $on_click = '', $sortable = true, $blank_message = '', $type = 'text', $input_name = '',$target=''){
        $c = new app_list_column($column_name, $column_header, $sortable, $column_url, $on_click, $format, $css_class, $blank_message, $type, $input_name,$target);
        $this->columns[] = $c;
    }//end function

    function get_page_url($page){
        if (!$this->is_initialized){
            die ("You must initialize the list by calling init_list() before calling get_page_url().");
        }
        $sort_by = $this->sort_by;
        $sort_dir = $this->sort_dir;
        $bad = false;
        //if we have a sort_url, it's because we need to pass arguments.
        // we may have a sort_url, or may not
        // if we do, it may or may not have already used the '?' char to set parameters
        if ($this->sort_url){
            if (strpos ($this->sort_url, '?') === false) {
               $url_delimiter = '?';
            } else {
               $url_delimiter = '&';
            }
        } else {
            $this->sort_url = $SERVER['PHP_SELF'];
            $url_delimiter = '?';
        }//end if

        if ($page == 'unspecified'){
            $r = $this->sort_url . $url_delimiter . "sort_by=" . $sort_by . "&sort_dir=" . $sort_dir . "&page_count=" . $this->page_count . "&page_length=" . $this->page_length;
            return $r;
        }

        if ($page == 'first'){
            $page = 1;
            if ($this->page == 1){
                $bad = true;
            }
        }//end if

        if ($page == 'last') {
            $page = $this->page_count;
            if ($this->page == $this->page_count){
                $bad = true;
            }
        }//end if

        if ($page == 'previous'){
            $page = $this->page - 1;
            if ($page < 1){
                $bad = true;
            }//end if

        }//end if

        if ($page == 'next'){
            $page = $this->page + 1;
            if ($page > $this->page_count){
                $bad = true;
            }//end if

        }//end if

        if ($bad == false){
            $r = $this->sort_url . $url_delimiter . "sort_by=" . $sort_by . "&sort_dir=" . $sort_dir . "&page=" . $page . "&page_count=" . $this->page_count . "&page_length=" . $this->page_length;
            return $r;
        } else {
            return false;
        }//end if

    }//end function get_page_url()
}//end class app_list

class app_list_column {
    var $column_name;
    var $column_header;
    var $sortable;
    var $column_url;
    var $on_click;
    var $format;
    var $css_class;
    var $blank_message;
    var $type;
    var $input_name;
    var $target;

    function app_list_column($column_name, $column_header, $sortable, $column_url, $on_click, $format, $css_class, $blank_message, $type, $input_name,$target){
        $this->column_name = $column_name;
        $this->column_header = $column_header;
        $this->sortable = $sortable;
        $this->column_url = $column_url;
        $this->on_click = $on_click;
        $this->format = $format;
        $this->css_class = $css_class;
        $this->blank_message = $blank_message;
        $this->type = $type;
        $this->input_name = $input_name;
        $this->target = $target;
    }// end function

    function format_value($value){
        switch ($this->format){
            case '':
                return $value;
                break;
            case 'date':
                return app_lib::nice_date($value, 'date');
                break;
            case 'datetime':
                return app_lib::nice_date($value, 'datetime');
                break;
            case 'yesno':
                if ($value){
                    return 'Yes';
                } else {
                    return 'No';
                }
                break;
            case 'abbreviated':
                if(strlen($value) > 20){
                    $value = substr($value, 0, 20) . "...";
                }// end if
                return $value;
                break;

            default:
                die ("There is no format called '$this->format' for columns.");

        }//end switch

    }
}//end class app_list_column



?>
